#include <iostream>
#include <map>
#include <caspp/caspp.h>
#include <gmp.h>

#include <boost/test/unit_test.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp>

#ifdef MYINT
#   error CHANGE
#endif
#define MYINT(WHAT) (WHAT)
#ifdef MYINTEGER
#   error CHANGE
#endif
#define MYINTEGER(WHAT) CASpp::Integer(MYINT(WHAT))
#define MYRATIONAL(NUM,DEN) CASpp::Rational(MYINTEGER(NUM),MYINTEGER(DEN))

struct MyObject {
    MyObject(){std::cout << "MyObject created" << std::endl;};
    ~MyObject(){std::cout << "MyObject destroyed" << std::endl;};
};
#define CASPP_REQUIRE_BOOLEAN(WHAT) BOOST_REQUIRE(CASpp::isTrue(WHAT))

#if 1
BOOST_AUTO_TEST_CASE(Wrap) {
    std::cout << "Testing Wrap..." <<  std::endl;
    CASpp::NodeRef nR;
    nR = CASpp::makeStringNodeRef("This is a test");
    typedef Shared::Wrap<CASpp::NodeRef> NodeRefWrap;
    NodeRefWrap nRW(nR);
    BOOST_REQUIRE(nR==nRW.element());
    nR = CASpp::makeStringNodeRef("This is another test");
    nRW.element() = nR;
    BOOST_REQUIRE(nR==nRW.element());
    {
        typedef Shared::Wrap<CASpp::NodeRefConst> NodeRefConstWrap;
        CASpp::NodeRef nR = CASpp::makeStringNodeRef("This is a test");
        NodeRefWrap nRW(nR);
        BOOST_REQUIRE(nR==nRW.element());
        nR = CASpp::makeStringNodeRef("This is another test");
        nRW.element() = nR;
        BOOST_REQUIRE(nR==nRW.element());
    }
    {
        typedef CASpp::Node Node;
        PAXER_DECLARE_TYPE_REF(Node);
        PAXER_DECLARE_TYPE_WRAP(NodeRef);
        NodeRef nR = CASpp::makeStringNodeRef("This is a test");
        NodeRefWrap nRW(nR);
        BOOST_REQUIRE(nR==nRW.element());
        nR = CASpp::makeStringNodeRef("This is another test");
        nRW.element() = nR;
        BOOST_REQUIRE(nR==nRW.element());
    }
    {
        typedef CASpp::Node Node;
        PAXER_DECLARE_TYPE_REF(Node);
        PAXER_DECLARE_TYPE_WRAP(NodeRef);
        NodeRefConst nR = CASpp::makeStringNodeRef("This is a test");
        NodeRefConstWrap nRW(nR);
        BOOST_REQUIRE(nR==nRW.element());
        //nR = CASpp::makeStringNodeRef("This is another test"); won't compile
        //nRW.element() = nR;; won't compile neither
        //BOOST_REQUIRE(nR==nRW.element());
    }
    {
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wlocal-type-template-args"
#endif
        class A {
        public:
            int ok() { return 123; }
        };
        class B {
        public:
            int ok() { return 543; }
        };
        class AB: public Shared::Wrap<A>, public Shared::Wrap<B> {
        public:
            typedef Shared::Wrap<A> __super_A;
            typedef Shared::Wrap<B> __super_B;
            AB(A & a, B & b):__super_A(a), __super_B(b) {}
            A & a() { return __super_A::element(); }
            B & b() { return __super_B::element(); }
        };
        A a;
        B b;
        AB ab(a,b);
        BOOST_REQUIRE(ab.a().ok()==123);
        BOOST_REQUIRE(ab.b().ok()==543);
#ifdef __clang__
#pragma clang diagnostic pop
#endif
    }
    std::cout << "DONE" << std::endl;
}

BOOST_AUTO_TEST_CASE(Map_stuff) {
    std::cout << "Map stuff:" << std::endl;
    std::cout << "- Assignment:" << std::endl;
    {
        CASpp::Map m;
        CASpp::NodeRef K = CASpp::makeStringNodeRef("COUCOU");
        CASpp::NodeRef V = m[K];
        BOOST_REQUIRE(V.get()==0);
        V = CASpp::makeIntegerNodeRef("20");
        m[K]=V;
        CASPP_REQUIRE_BOOLEAN(m[K]==V);
        {
            CASpp::Map mm;
            CASpp::Comparison c = compare(m,mm);
            BOOST_REQUIRE(c.isDescending());
            c = compare(mm,m);
            BOOST_REQUIRE(c.isAscending());
        }
    }
    std::cout << "- compare:" << std::endl;
    short range[] = { 0, 1, 2 };
    short ranges[3][2] = {{1,2},{0,2},{0,1}};
    boost::array<const char*,3> Cs ={{"0","1","2"}};
    boost::array<CASpp::NodeRef,3> NRs;
    BOOST_FOREACH (const size_t i,range) {
        NRs[i]=CASpp::makeIntegerNodeRef(std::string(Cs[i]));
    }
#define REQUIRE_L_LESS_THAN_R \
    BOOST_REQUIRE((L < R).isTrue() && (R > L).isTrue() && (L >= R).isFalse() && (R <= L).isFalse())
#define REQUIRE_L_GREATER_THAN_R \
    BOOST_REQUIRE((L > R).isTrue() && (R < L).isTrue() && (L <= R).isFalse() && (R >= L).isFalse())
#define REQUIRE_L_EQUALS_R \
    BOOST_REQUIRE((L == R).isTrue() && (L != R).isFalse())

    std::cout << "Compare 0/0" << std:: endl;
    {
        CASpp::Map L;
        CASpp::Map R;
        CASpp::Comparison c = compare(L,R);
        BOOST_REQUIRE(c.isSame());
        CASPP_REQUIRE_BOOLEAN(L==R);
        BOOST_REQUIRE((L==R).isTrue());
    }
    std::cout << "Compare 0/1" << std:: endl;
    {
        CASpp::Map L;
        CASpp::Map R;
        R[NRs[0]]=NRs[0];
        BOOST_REQUIRE((L<R).isTrue());
        BOOST_REQUIRE((R>L).isTrue());
    }
    std::cout << "Compare 1/1" << std:: endl;
    {
        BOOST_FOREACH (const size_t i,range) {
            BOOST_FOREACH (const size_t j,range) {
                CASpp::Map L;
                L[NRs[i]]=NRs[j];
                BOOST_FOREACH (const size_t k,range) {
                    BOOST_FOREACH (const size_t l,range) {
                        CASpp::Map R;
                        R[NRs[k]]=NRs[l];
                        if (i<k) {
                            REQUIRE_L_LESS_THAN_R;
                        } else if (i>k) {
                            REQUIRE_L_GREATER_THAN_R;
                        } else if (j<l) {
                            REQUIRE_L_LESS_THAN_R;
                        } else if (j>l) {
                            REQUIRE_L_GREATER_THAN_R;
                        } else {
                            REQUIRE_L_EQUALS_R;
                        }
                    }
                }
            }
        }
    }
    std::cout << "Compare 1/2" << std:: endl;
    {
        BOOST_FOREACH (const size_t i,range) {
            BOOST_FOREACH (const size_t j,range) {
                CASpp::Map L;
                L[NRs[i]]=NRs[j];
                BOOST_FOREACH (const size_t k,range) {
                    BOOST_FOREACH (const size_t l,range) {
                        CASpp::Map R;
                        R[NRs[k]]=NRs[l];
                        if (i<k) {
                            BOOST_FOREACH (const size_t m,ranges[k]) {
                                if (i<m) {
                                    BOOST_FOREACH (const size_t n,range) {
                                        R[NRs[m]]=NRs[n];
                                        REQUIRE_L_LESS_THAN_R;
                                        R.erase(NRs[m]);
                                    }
                                } else if (i==m) {
                                    BOOST_FOREACH (const size_t n,range) {
                                        if (j<n) {
                                            R[NRs[m]]=NRs[n];
                                            REQUIRE_L_LESS_THAN_R;
                                            R.erase(NRs[m]);
                                        } else if (j>n) {
                                            R[NRs[m]]=NRs[n];
                                            REQUIRE_L_GREATER_THAN_R;
                                            R.erase(NRs[m]);
                                        }
                                    }
                                } else /* if (i>m) */ {
                                    BOOST_FOREACH (const size_t n,range) {
                                        R[NRs[m]]=NRs[n];
                                        REQUIRE_L_GREATER_THAN_R;
                                        R.erase(NRs[m]);
                                    }
                                }
                            }
                        } else if (i>k) {
                            REQUIRE_L_GREATER_THAN_R;
                            BOOST_FOREACH (const size_t m,ranges[k]) {
                                if (i!=m) {
                                    BOOST_FOREACH (const size_t n,range) {
                                        R[NRs[m]]=NRs[n];
                                        REQUIRE_L_GREATER_THAN_R;
                                        R.erase(NRs[m]);
                                    }
                                }
                            }
                        } else if /*(i==k) AND */ (j<l) {
                            REQUIRE_L_LESS_THAN_R;
                            BOOST_FOREACH (const size_t m,ranges[k]) {
                                if (i<m) {
                                    BOOST_FOREACH (const size_t n,range) {
                                        R[NRs[m]]=NRs[n];
                                        REQUIRE_L_LESS_THAN_R;
                                        R.erase(NRs[m]);
                                    }
                                } else if (i==m) {
                                    // do not override the previous right node
                                } else {
                                    BOOST_FOREACH (const size_t n,range) {
                                        R[NRs[m]]=NRs[n];
                                        REQUIRE_L_GREATER_THAN_R;
                                        R.erase(NRs[m]);
                                    }
                                }
                            }
                        } else if /*(i==k) AND */ (j>l) {
                            REQUIRE_L_GREATER_THAN_R;
                            BOOST_FOREACH (const size_t m,ranges[k]) {
                                BOOST_FOREACH (const size_t n,range) {
                                    R[NRs[m]]=NRs[n];
                                    REQUIRE_L_GREATER_THAN_R;
                                    R.erase(NRs[m]);
                                }
                            }
                        } else /* if (i==k) AND (j==l) */{
                            BOOST_REQUIRE((L == R).isTrue());
                            BOOST_FOREACH (const size_t m,ranges[k]) {
                                BOOST_FOREACH (const size_t n,range) {
                                    R[NRs[m]]=NRs[n];
                                    if (i<m) {
                                        REQUIRE_L_LESS_THAN_R;
                                    } else if (i>m) {
                                        REQUIRE_L_GREATER_THAN_R;
                                    } else {
                                        // unreachable code
                                        BOOST_REQUIRE(false);
                                    }
                                    R.erase(NRs[m]);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    std::cout << "Compare 2/2" << std:: endl;
    {
        BOOST_FOREACH (const size_t i,range) {
            BOOST_FOREACH (const size_t j,range) {
                CASpp::Map L;
                L[NRs[i]]=NRs[j];
                BOOST_FOREACH (const size_t k,range) {
                    BOOST_FOREACH (const size_t l,range) {
                        CASpp::Map R;
                        R[NRs[k]]=NRs[l];
                        if (i<k) {
                            BOOST_FOREACH (const size_t m,ranges[k]) {
                                if (i<m) {
                                    BOOST_FOREACH (const size_t n,range) {
                                        R[NRs[m]]=NRs[n];
                                        REQUIRE_L_LESS_THAN_R;
                                        BOOST_FOREACH (const size_t o,ranges[i]) {
                                            BOOST_FOREACH (const size_t p,range) {
                                                L[NRs[o]]=NRs[p];
                                                REQUIRE_L_LESS_THAN_R;
                                                L.erase(NRs[o]);
                                            }
                                        }
                                        R.erase(NRs[m]);
                                    }
                                } else if (i==m) {
                                    BOOST_FOREACH (const size_t n,range) {
                                        if (j<n) {
                                            R[NRs[m]]=NRs[n];
                                            REQUIRE_L_LESS_THAN_R;
                                            BOOST_FOREACH (const size_t o,ranges[i]) {
                                                BOOST_FOREACH (const size_t p,range) {
                                                    L[NRs[o]]=NRs[p];
                                                    REQUIRE_L_LESS_THAN_R;
                                                    L.erase(NRs[o]);
                                                }
                                            }
                                            R.erase(NRs[m]);
                                        } else if (j>n) {
                                            R[NRs[m]]=NRs[n];
                                            REQUIRE_L_GREATER_THAN_R;
                                            BOOST_FOREACH (const size_t o,ranges[i]) {
                                                if (i<o) {
                                                    BOOST_FOREACH (const size_t p,range) {
                                                        L[NRs[o]]=NRs[p];
                                                        REQUIRE_L_GREATER_THAN_R;
                                                        L.erase(NRs[o]);
                                                    }
                                                } else /* if (i>o) */ {
                                                    BOOST_FOREACH (const size_t p,range) {
                                                        L[NRs[o]]=NRs[p];
                                                        REQUIRE_L_LESS_THAN_R;
                                                        L.erase(NRs[o]);
                                                    }
                                                }
                                            }
                                            R.erase(NRs[m]);
                                        }
                                    }
                                } else /* if (i>m) */ {
                                    BOOST_FOREACH (const size_t n,range) {
                                        R[NRs[m]]=NRs[n];
                                        REQUIRE_L_GREATER_THAN_R;
                                        BOOST_FOREACH (const size_t o,ranges[i]) {
                                            if (i<o) {
                                                BOOST_FOREACH (const size_t p,range) {
                                                    L[NRs[o]]=NRs[p];
                                                    REQUIRE_L_GREATER_THAN_R;
                                                    L.erase(NRs[o]);
                                                }
                                            } else if (o>m) {
                                                BOOST_FOREACH (const size_t p,range) {
                                                    L[NRs[o]]=NRs[p];
                                                    REQUIRE_L_GREATER_THAN_R;
                                                    L.erase(NRs[o]);
                                                }
                                            } else if (o==m) {
                                                BOOST_FOREACH (const size_t p,range) {
                                                    L[NRs[o]]=NRs[p];
                                                    if (p>n) {
                                                        REQUIRE_L_GREATER_THAN_R;
                                                    } else /* if (p<=n) */ {
                                                        REQUIRE_L_LESS_THAN_R;
                                                    }
                                                    L.erase(NRs[o]);
                                                }
                                            } else /* if (m>o) */ {
                                                BOOST_FOREACH (const size_t p,range) {
                                                    L[NRs[o]]=NRs[p];
                                                    REQUIRE_L_GREATER_THAN_R;
                                                    L.erase(NRs[o]);
                                                }
                                            }
                                        }
                                        R.erase(NRs[m]);
                                    }
                                }
                            }
                        } else if (i>k) {
                            REQUIRE_L_GREATER_THAN_R;
                            BOOST_FOREACH (const size_t m,ranges[k]) {
                                BOOST_FOREACH (const size_t n,range) {
                                    R[NRs[m]]=NRs[n];
                                    REQUIRE_L_GREATER_THAN_R;
                                    BOOST_FOREACH (const size_t o,ranges[i]) {
                                        if (k<m) {
                                            if(o<k) {
                                                BOOST_FOREACH (const size_t p,range) {
                                                    L[NRs[o]]=NRs[p];
                                                    REQUIRE_L_LESS_THAN_R;
                                                    L.erase(NRs[o]);
                                                }
                                            } else if (o==k) {
                                                BOOST_FOREACH (const size_t p,range) {
                                                    L[NRs[o]]=NRs[p];
                                                    if (p<l) {
                                                        REQUIRE_L_LESS_THAN_R;
                                                    } else if (p==l) {
                                                        if (i<m) {
                                                            REQUIRE_L_LESS_THAN_R;
                                                        } else if (i==m) {
                                                            if (j<n) {
                                                                REQUIRE_L_LESS_THAN_R;
                                                            } else if (j==n) {
                                                                REQUIRE_L_EQUALS_R;
                                                            } else {
                                                                REQUIRE_L_GREATER_THAN_R;
                                                            }
                                                        } else /* if (i>m) */ {
                                                            REQUIRE_L_GREATER_THAN_R;
                                                        }
                                                    } else {
                                                        REQUIRE_L_GREATER_THAN_R;
                                                    }
                                                    L.erase(NRs[o]);
                                                }
                                            } else /* if (o>k) */ {
                                                BOOST_FOREACH (const size_t p,range) {
                                                    L[NRs[o]]=NRs[p];
                                                    REQUIRE_L_GREATER_THAN_R;
                                                    L.erase(NRs[o]);
                                                }
                                            }
                                        } else /* if (k>m) */ {
                                            if(o<m) {
                                                BOOST_FOREACH (const size_t p,range) {
                                                    L[NRs[o]]=NRs[p];
                                                    REQUIRE_L_LESS_THAN_R;
                                                    L.erase(NRs[o]);
                                                }
                                            } else if (o==m) {
                                                BOOST_FOREACH (const size_t p,range) {
                                                    L[NRs[o]]=NRs[p];
                                                    if (p<n) {
                                                        REQUIRE_L_LESS_THAN_R;
                                                    } else if (p==n) {
                                                        REQUIRE_L_GREATER_THAN_R;
                                                    } else /* if (p>n) */ {
                                                        REQUIRE_L_GREATER_THAN_R;
                                                    }
                                                    L.erase(NRs[o]);
                                                }
                                            } else /* if (o>m) */ {
                                                BOOST_FOREACH (const size_t p,range) {
                                                    L[NRs[o]]=NRs[p];
                                                    REQUIRE_L_GREATER_THAN_R;
                                                    L.erase(NRs[o]);
                                                }
                                            }
                                        }
                                    }
                                    R.erase(NRs[m]);
                                }
                            }
                        } else if /*(i==k) AND */ (j<l) {
                            REQUIRE_L_LESS_THAN_R;
                            BOOST_FOREACH (const size_t m,ranges[k]) {
                                if (k<m) {
                                    BOOST_FOREACH (const size_t n,range) {
                                        R[NRs[m]]=NRs[n];
                                        REQUIRE_L_LESS_THAN_R;
                                        BOOST_FOREACH (const size_t o,ranges[i]) {
                                            BOOST_FOREACH (const size_t p,range) {
                                               L[NRs[o]]=NRs[p];
                                               REQUIRE_L_LESS_THAN_R;
                                               L.erase(NRs[o]);
                                            }
                                        }
                                        R.erase(NRs[m]);
                                    }
                                } else /* if (k>m) */ {
                                    BOOST_FOREACH (const size_t n,range) {
                                        R[NRs[m]]=NRs[n];
                                        REQUIRE_L_GREATER_THAN_R;
                                        BOOST_FOREACH (const size_t o,ranges[i]) {
                                            BOOST_FOREACH (const size_t p,range) {
                                               L[NRs[o]]=NRs[p];
                                               if (o<m) {
                                                   REQUIRE_L_LESS_THAN_R;
                                               } else if (o==m) {
                                                   if (p<n) {
                                                       REQUIRE_L_LESS_THAN_R;
                                                   } else if (p==n) {
                                                       REQUIRE_L_LESS_THAN_R;
                                                   } else {
                                                       REQUIRE_L_GREATER_THAN_R;
                                                   }
                                               } else {
                                                   REQUIRE_L_GREATER_THAN_R;
                                               }
                                               L.erase(NRs[o]);
                                            }
                                        }
                                        R.erase(NRs[m]);
                                    }
                                }
                            }
                        } else if /*(i==k) AND */ (j>l) {
                            REQUIRE_L_GREATER_THAN_R;
                            BOOST_FOREACH (const size_t m,ranges[k]) {
                                BOOST_FOREACH (const size_t n,range) {
                                    R[NRs[m]]=NRs[n];
                                    REQUIRE_L_GREATER_THAN_R;
                                    BOOST_FOREACH (const size_t o,ranges[i]) {
                                        BOOST_FOREACH (const size_t p,range) {
                                            L[NRs[o]]=NRs[p];
                                            if (k<m) {
                                                if (o<k) {
                                                    REQUIRE_L_LESS_THAN_R;
                                                } else /* if (o>k) */ {
                                                    REQUIRE_L_GREATER_THAN_R;
                                                }
                                            } else /* if (m<k) */ {
                                                if (o<m) {
                                                    REQUIRE_L_LESS_THAN_R;
                                                } else if (o==m) {
                                                    if (p<n) {
                                                        //std::cout<<i<<","<<o<<","<<k<<","<<m<<std::endl<<j<<","<<p<<","<<l<<","<<n<<std::endl;
                                                        //std::cout<<CASpp::longDescription(L,"L")<<std::endl<<CASpp::longDescription(R,"R")<<std::endl;
                                                        REQUIRE_L_LESS_THAN_R;
                                                    } else if (p==n) {
                                                        REQUIRE_L_GREATER_THAN_R;
                                                    } else /* if (p>n) */ {
                                                        REQUIRE_L_GREATER_THAN_R;
                                                    }
                                                } else /* if (o>k) */ {
                                                    REQUIRE_L_GREATER_THAN_R;
                                                }
                                            }
                                            L.erase(NRs[o]);
                                        }
                                    }
                                    R.erase(NRs[m]);
                                }
                            }
                        } else /* if (i==k) AND (j==l) */{
                            REQUIRE_L_EQUALS_R;
                            BOOST_FOREACH (const size_t m,ranges[k]) {
                                BOOST_FOREACH (const size_t n,range) {
                                    R[NRs[m]]=NRs[n];
                                    if (i<m) {
                                        REQUIRE_L_LESS_THAN_R;
                                        BOOST_FOREACH (const size_t o,ranges[i]) {
                                            BOOST_FOREACH (const size_t p,range) {
                                                L[NRs[o]]=NRs[p];
                                                if (o<m) {
                                                    REQUIRE_L_LESS_THAN_R;
                                                } else if (o==m) {
                                                    if (p<n) {
                                                        REQUIRE_L_LESS_THAN_R;
                                                    } else if (p==n) {
                                                        REQUIRE_L_EQUALS_R;
                                                    } else /*  if (p>n)*/ {
                                                        REQUIRE_L_GREATER_THAN_R;
                                                    }
                                                } else /*  if (o>m)*/ {
                                                    REQUIRE_L_GREATER_THAN_R;
                                                }
                                                L.erase(NRs[o]);
                                            }
                                        }
                                    } else /* if (i>m) */ {
                                        REQUIRE_L_GREATER_THAN_R;
                                        BOOST_FOREACH (const size_t o,ranges[i]) {
                                            BOOST_FOREACH (const size_t p,range) {
                                                L[NRs[o]]=NRs[p];
                                                if (o<m) {
                                                    REQUIRE_L_LESS_THAN_R;
                                                } else if (o==m) {
                                                    if (p<n) {
                                                        REQUIRE_L_LESS_THAN_R;
                                                    } else if (p==n) {
                                                        REQUIRE_L_EQUALS_R;
                                                    } else /*  if (p>n)*/ {
                                                        REQUIRE_L_GREATER_THAN_R;
                                                    }
                                                } else /*  if (o>m)*/ {
                                                    REQUIRE_L_GREATER_THAN_R;
                                                }
                                                L.erase(NRs[o]);
                                            }
                                        }
                                    }
                                    R.erase(NRs[m]);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
#undef REQUIRE_L_LESS_THAN_R
#undef REQUIRE_L_GREATER_THAN_R
#undef REQUIRE_L_EQUALS_R
}
BOOST_AUTO_TEST_CASE(Vector_stuff) {
    std::cout << "Vector stuff:" << std::endl;
    CASpp::Vector v;
    BOOST_REQUIRE(v.size()==0);
    std::string s = "0";
    v.push_back(CASpp::makeStringNodeRef(s));
    CASpp::NodeRef n = v[0];
    CASpp::NodeRef nn = CASpp::makeStringNodeRef(s);
    BOOST_REQUIRE(v.size()==1);
    CASPP_REQUIRE_BOOLEAN(n==nn);
    v.push_back(CASpp::makeStringNodeRef("1"));
    BOOST_REQUIRE(v.size()==2);
    CASPP_REQUIRE_BOOLEAN(v[0]==CASpp::makeStringNodeRef("0"));
    CASPP_REQUIRE_BOOLEAN(v[1]==CASpp::makeStringNodeRef("1"));
    v.pop_back();
    BOOST_REQUIRE(v.size()==1);
    CASPP_REQUIRE_BOOLEAN(v[0]==CASpp::makeStringNodeRef("0"));
    v.push_back(CASpp::makeStringNodeRef("1"));
    BOOST_REQUIRE(v.size()==2);
    CASPP_REQUIRE_BOOLEAN(v[0]==CASpp::makeStringNodeRef("0"));
    CASPP_REQUIRE_BOOLEAN(v[1]==CASpp::makeStringNodeRef("1"));
    v.erase(v.begin());
    BOOST_REQUIRE(v.size()==1);
    CASPP_REQUIRE_BOOLEAN(v[0]==CASpp::makeStringNodeRef("1"));
}
BOOST_AUTO_TEST_CASE(Boolean_stuff) {
    std::cout << "Boolean tests" <<  std::endl;
    BOOST_REQUIRE_THROW(CASpp::Boolean(""),std::runtime_error);
    BOOST_REQUIRE_THROW(CASpp::Boolean("BLABLABLA"),std::runtime_error);
    std::cout << "Creation with value" <<  std::endl;
    typedef boost::tuple<bool,bool,bool,CASpp::Boolean::Values> myBooleanTuple1;
    boost::array<myBooleanTuple1,4> BTs = {
        { myBooleanTuple1(false, false, false, CASpp::Boolean::kUndefined)
        , myBooleanTuple1(true,  false, false, CASpp::Boolean::kTrue)
        , myBooleanTuple1(false, true,  false, CASpp::Boolean::kFalse)
        , myBooleanTuple1(false, false, true,  CASpp::Boolean::kUnknown)
        } };
    BOOST_FOREACH(myBooleanTuple1 bt, BTs) {
        CASpp::Boolean b(bt.get<3>());
        BOOST_REQUIRE(b.isTrue()==bt.get<0>());
        BOOST_REQUIRE(b.isFalse()==bt.get<1>());
        BOOST_REQUIRE(b.isUnknown()==bt.get<2>());
    }
    std::cout << "Creation with boolean" <<  std::endl;
    typedef boost::tuple<bool,bool,bool,bool> myBooleanTuple2;
    boost::array<myBooleanTuple2,2> BTs2 = {
        { myBooleanTuple2(true,  false, false, true)
        , myBooleanTuple2(false, true,  false, false)
        } };
    BOOST_FOREACH(myBooleanTuple2 bt, BTs2) {
        CASpp::Boolean b(bt.get<3>());
        BOOST_REQUIRE(b.isTrue()==bt.get<0>());
        BOOST_REQUIRE(b.isFalse()==bt.get<1>());
        BOOST_REQUIRE(b.isUnknown()==bt.get<2>());
    }
    std::cout << "operator !" <<  std::endl;
    boost::array<myBooleanTuple1,4> notBTs = {
        { myBooleanTuple1(false, false, false, CASpp::Boolean::kUndefined)
        , myBooleanTuple1(false, true,  false, CASpp::Boolean::kTrue)
        , myBooleanTuple1(true,  false, false, CASpp::Boolean::kFalse)
        , myBooleanTuple1(false, false, true,  CASpp::Boolean::kUnknown)
        } };
    BOOST_FOREACH(myBooleanTuple1 bt, notBTs) {
        CASpp::Boolean b(bt.get<3>());
        b = !b;
        BOOST_REQUIRE(b.isTrue()==bt.get<0>());
        BOOST_REQUIRE(b.isFalse()==bt.get<1>());
        BOOST_REQUIRE(b.isUnknown()==bt.get<2>());
    }
    std::cout << "operator &&" <<  std::endl;
    typedef boost::tuple<bool,bool,bool,CASpp::Boolean::Values,CASpp::Boolean::Values> myBooleanTuple3;
    boost::array<myBooleanTuple3,16> BTs3AND = {
        { myBooleanTuple3(false, false, false, CASpp::Boolean::kUndefined, CASpp::Boolean::kUndefined)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kUndefined, CASpp::Boolean::kTrue)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kUndefined, CASpp::Boolean::kFalse)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kUndefined, CASpp::Boolean::kUnknown)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kTrue,      CASpp::Boolean::kUndefined)
          , myBooleanTuple3(true,  false, false, CASpp::Boolean::kTrue,      CASpp::Boolean::kTrue)
          , myBooleanTuple3(false, true,  false, CASpp::Boolean::kTrue,      CASpp::Boolean::kFalse)
          , myBooleanTuple3(false, false, true,  CASpp::Boolean::kTrue,      CASpp::Boolean::kUnknown)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kFalse,     CASpp::Boolean::kUndefined)
          , myBooleanTuple3(false, true,  false, CASpp::Boolean::kFalse,     CASpp::Boolean::kTrue)
          , myBooleanTuple3(false, true,  false, CASpp::Boolean::kFalse,     CASpp::Boolean::kFalse)
          , myBooleanTuple3(false, false, true,  CASpp::Boolean::kFalse,     CASpp::Boolean::kUnknown)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kUnknown,   CASpp::Boolean::kUndefined)
          , myBooleanTuple3(false, false, true,  CASpp::Boolean::kUnknown,   CASpp::Boolean::kTrue)
          , myBooleanTuple3(false, false, true,  CASpp::Boolean::kUnknown,   CASpp::Boolean::kFalse)
          , myBooleanTuple3(false, false, true,  CASpp::Boolean::kUnknown,   CASpp::Boolean::kUnknown)
        } };
    BOOST_FOREACH(myBooleanTuple3 bt, BTs3AND) {
//        std::cout << "tester " << bt.get<0>() << ", " << bt.get<1>() << ", " << bt.get<2>() << ", " << bt.get<3>() << ", " << bt.get<4>() << ", " << std::endl;
        CASpp::Boolean b1(bt.get<3>());
        CASpp::Boolean b2(bt.get<4>());
        CASpp::Boolean b(b1&&b2);
        BOOST_REQUIRE(b.isTrue()==bt.get<0>());
        BOOST_REQUIRE(b.isFalse()==bt.get<1>());
        BOOST_REQUIRE(b.isUnknown()==bt.get<2>());
    }
    std::cout << "operator ||" <<  std::endl;
    boost::array<myBooleanTuple3,16> BTs3OR = {
        { myBooleanTuple3(false, false, false, CASpp::Boolean::kUndefined, CASpp::Boolean::kUndefined)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kUndefined, CASpp::Boolean::kTrue)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kUndefined, CASpp::Boolean::kFalse)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kUndefined, CASpp::Boolean::kUnknown)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kTrue,      CASpp::Boolean::kUndefined)
          , myBooleanTuple3(true,  false, false, CASpp::Boolean::kTrue,      CASpp::Boolean::kTrue)
          , myBooleanTuple3(true,  false, false, CASpp::Boolean::kTrue,      CASpp::Boolean::kFalse)
          , myBooleanTuple3(false, false, true,  CASpp::Boolean::kTrue,      CASpp::Boolean::kUnknown)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kFalse,     CASpp::Boolean::kUndefined)
          , myBooleanTuple3(true,  false, false, CASpp::Boolean::kFalse,     CASpp::Boolean::kTrue)
          , myBooleanTuple3(false, true,  false, CASpp::Boolean::kFalse,     CASpp::Boolean::kFalse)
          , myBooleanTuple3(false, false, true,  CASpp::Boolean::kFalse,     CASpp::Boolean::kUnknown)
          , myBooleanTuple3(false, false, false, CASpp::Boolean::kUnknown,   CASpp::Boolean::kUndefined)
          , myBooleanTuple3(false, false, true,  CASpp::Boolean::kUnknown,   CASpp::Boolean::kTrue)
          , myBooleanTuple3(false, false, true,  CASpp::Boolean::kUnknown,   CASpp::Boolean::kFalse)
          , myBooleanTuple3(false, false, true,  CASpp::Boolean::kUnknown,   CASpp::Boolean::kUnknown)
        } };
    BOOST_FOREACH(myBooleanTuple3 bt, BTs3OR) {
//        std::cout << "tester " << bt.get<0>() << ", " << bt.get<1>() << ", " << bt.get<2>() << ", " << bt.get<3>() << ", " << bt.get<4>() << ", " << std::endl;
        CASpp::Boolean b1(bt.get<3>());
        CASpp::Boolean b2(bt.get<4>());
        CASpp::Boolean b(b1||b2);
        BOOST_REQUIRE(b.isTrue()==bt.get<0>());
        BOOST_REQUIRE(b.isFalse()==bt.get<1>());
        BOOST_REQUIRE(b.isUnknown()==bt.get<2>());
    }
    std::cout << "makeBooleanRef" <<  std::endl;
    typedef boost::tuple<bool,bool,bool,std::string> myBooleanTuple4;
    boost::array<myBooleanTuple4,2> BTs4 = {
    {  myBooleanTuple4(true,  false, false, "Vrai")
     , myBooleanTuple4(false, true,  false, "Faux")
    } };
    BOOST_FOREACH(myBooleanTuple4 bt, BTs4) {
//        std::cout << "tester " << bt.get<0>() << ", " << bt.get<1>() << ", " << bt.get<2>() << ", " << bt.get<3>() << ", " << bt.get<4>() << ", " << std::endl;
        CASpp::Boolean b(bt.get<3>());
        BOOST_REQUIRE(b.isTrue()==bt.get<0>());
        BOOST_REQUIRE(b.isFalse()==bt.get<1>());
        BOOST_REQUIRE(b.isUnknown()==bt.get<2>());
    }
    BOOST_REQUIRE_THROW(CASpp::Boolean(""),std::runtime_error);
    BOOST_REQUIRE_THROW(CASpp::Boolean("BLABLABLA"),std::runtime_error);
    BOOST_FOREACH(myBooleanTuple4 bt, BTs4) {
        //std::cout << "tester " << bt.get<0>() << ", " << bt.get<1>() << ", " << bt.get<2>() << ", " << bt.get<3>() << std::endl;
        CASpp::BooleanRef b = CASpp::BooleanRef(new CASpp::BooleanRef::element_type(bt.get<3>()));
        BOOST_REQUIRE(b->isTrue()   ==bt.get<0>());
        BOOST_REQUIRE(b->isFalse()  ==bt.get<1>());
        BOOST_REQUIRE(b->isUnknown()==bt.get<2>());
    }
    {
        BOOST_REQUIRE_THROW(CASpp::Boolean("ABCD"),std::runtime_error);
        CASpp::Node n("ABCD",CASpp::Type::kAUTO);
        BOOST_REQUIRE(!n.isBoolean());
        CASpp::NodeRef nr = CASpp::NodeRef(new CASpp::Node("",CASpp::Type::kAUTO));
        BOOST_REQUIRE_THROW(nr->booleanRef(),CASpp::Node::BadRef);
        BOOST_REQUIRE(nr->isString());
        BOOST_REQUIRE(!nr->isBoolean());
        nr = CASpp::NodeRef(new CASpp::Node("ABCD",CASpp::Type::kAUTO));
        BOOST_REQUIRE_THROW(nr->booleanRef(),CASpp::Node::BadRef);
        BOOST_REQUIRE(nr->isString());
        BOOST_REQUIRE(!nr->isBoolean());
    }
}
BOOST_AUTO_TEST_CASE(Node_stuff) {
    std::cout << "Node type" <<  std::endl;
    {
        CASpp::Node n;
        BOOST_REQUIRE(n.type() == CASpp::Type::kUNDEF);
    }
    {
        CASpp::Node n(CASpp::Integer("12"));
        BOOST_REQUIRE(n.type() == CASpp::Type::kINT);
    }
    {
        CASpp::Node n(CASpp::Rational("3/4"));
        BOOST_REQUIRE(n.type() == CASpp::Type::kRAT);
    }
    {
        CASpp::Node n(CASpp::Real("3.14"));
        BOOST_REQUIRE(n.type() == CASpp::Type::kREAL);
    }
    {
        CASpp::Node n1(CASpp::Integer(1));
        CASpp::Node n2(CASpp::Integer(2));
        CASpp::IntegerRef r1 = boost::get<CASpp::IntegerRef>(n1);
        CASpp::IntegerRef r2 = boost::get<CASpp::IntegerRef>(n2);
        CASpp::Integer * x1 = r1.get();
        CASpp::Integer * x2 = r2.get();
//        BOOST_REQUIRE(n1!=n2);
        BOOST_REQUIRE(r1!=r2);
        BOOST_REQUIRE(x1!=x2);
        n2 = n1;
        r2 = boost::get<CASpp::IntegerRef>(n2);
        x2 = r2.get();
//        BOOST_REQUIRE(n1==n2);
        BOOST_REQUIRE(r1==r2);
        BOOST_REQUIRE(x1==x2);
        n1 = CASpp::Integer(11);
        r1 = boost::get<CASpp::IntegerRef>(n1);
        x1 = r1.get();
        //        BOOST_REQUIRE(n1!=n2);
        BOOST_REQUIRE(r1!=r2);
        BOOST_REQUIRE(x1!=x2);
        r2=r1;
        x2 = r2.get();
        //        BOOST_REQUIRE(n1=n2);
        BOOST_REQUIRE(r1=r2);
        BOOST_REQUIRE(x1=x2);
    }
    {
        std::cout << "makeIntegerRef:" << std::endl;
        std::string d = "12345";
        CASpp::NodeRef r = CASpp::makeIntegerNodeRef(d);
        BOOST_REQUIRE(d == r->description());
    }
    {
        std::cout << "makeRationalRef:" << std::endl;
        std::string d = "2/3";
        CASpp::NodeRef r = CASpp::makeRationalNodeRef(d);
        BOOST_REQUIRE(d == r->description());
    }
    {
        std::cout << "makeRealRef:" << std::endl;
        std::string d = "1.0";
        CASpp::NodeRef r = CASpp::makeRealNodeRef(d);
        BOOST_REQUIRE(d == r->description().substr(0,d.length()));
    }
    {
        std::cout << "makeStringRef:" << std::endl;
        std::string d = "abcde";
        CASpp::NodeRef r = CASpp::makeStringNodeRef(d);
        BOOST_REQUIRE(d == r->description());
    }
    {
        std::cout << "makeSymbolRef:" << std::endl;
        std::string d = "abcde";
        CASpp::NodeRef r = CASpp::makeSymbolNodeRef(d);
        BOOST_REQUIRE(d == r->description());
    }
    {
        std::cout << "makeFunctionRef:" << std::endl;
        std::string d = "abcde";
        CASpp::NodeRef r = CASpp::makeFunctionNodeRef(d);
        BOOST_REQUIRE(d == r->description().substr(0,d.length()));
    }
    {
        std::cout << "Node reference assignment:" << std::endl;
        CASpp::Node n(CASpp::Integer(12345));
        std::string d = "54321";
        n.integerRef() = CASpp::IntegerRef(new CASpp::Integer(d));
        CASpp::Node m(n);
        BOOST_REQUIRE(m.description() == "54321");
    }
    {
        std::cout << "Nodes cumulative assignments: different types" << std::endl;
        CASpp::Node n(CASpp::Integer(12345));
        n = CASpp::Node(CASpp::Integer(54321));
        BOOST_REQUIRE(n.type() == CASpp::Type::kINT);
        n = CASpp::Node(CASpp::Rational("2/3"));
        BOOST_REQUIRE(n.type() == CASpp::Type::kRAT);
        n = CASpp::Node(CASpp::Real(1.234));
        BOOST_REQUIRE(n.type() == CASpp::Type::kREAL);
        n = CASpp::Node(CASpp::String("abcde"));
        BOOST_REQUIRE(n.type() == CASpp::Type::kSTR);
    }
    std::cout << "Node(string,type) creation:" << std::endl;
    {
        std::string s;
        CASpp::Type::Unary t;
        CASpp::Node n;
        s = "1234";
        t = CASpp::Type::kAUTO;
        CASpp::Node * p = new CASpp::NodeRef::element_type(std::string(s),t);
        CASpp::NodeRef r;
        r.reset(p);
        BOOST_REQUIRE(r->type() == CASpp::Type::kINT);
        BOOST_REQUIRE(r->description() == s);
        s = "1234";
        t = CASpp::Type::kAUTO;
        r = CASpp::NodeRef(new CASpp::Node(s,t));
        BOOST_REQUIRE(r->type() == CASpp::Type::kINT);
        BOOST_REQUIRE(r->description() == s);
        {
            CASpp::NodeRef rr;
            rr = CASpp::NodeRef(new CASpp::Node(s,CASpp::Type::kUNDEF));
            BOOST_REQUIRE(rr->type() == CASpp::Type::kINT);
            rr = CASpp::NodeRef(new CASpp::Node(s,CASpp::Type::kAUTO));
            BOOST_REQUIRE(rr->type() == CASpp::Type::kINT);
        }
#define CASPP_DO(__V) CASpp::Type::__V
        std::cout << "test string :" << s << std::endl;
        CASpp::Type::Array types = {{ CASPP_ALL_NODE_TYPES(CASPP_DO) }};
#undef CASPP_DO
        BOOST_FOREACH(CASpp::Type::Array::value_type t, types) {
            //std::cout << "for type:" << CASpp::Type::name(t) << "("<<t<<")... ";
            r = CASpp::NodeRef(new CASpp::Node(s,t));
            //std::cout << "got type:" << r->prettyType() << "("<<r->type()<<")... ";
            switch(t) {
            case CASpp::Type::kUNDEF:
                BOOST_REQUIRE(r->type() == CASpp::Type::kINT);
                BOOST_REQUIRE(r->description() == s);
                break;
            case CASpp::Type::kINT:
            case CASpp::Type::kRAT:
            case CASpp::Type::kSTR:
            case CASpp::Type::kSYMB:
            case CASpp::Type::kVAR:
                BOOST_REQUIRE(r->description() == s);
            case CASpp::Type::kREAL:
            case CASpp::Type::kVECT:
            case CASpp::Type::kMAP:
            case CASpp::Type::kFUNC:
                BOOST_REQUIRE(r->type() == t);
                break;
            default:
                BOOST_REQUIRE(r->type() == CASpp::Type::kUNDEF);
                break;
            }
            //std::cout << "done" << std::endl;
        }
    }
}
BOOST_AUTO_TEST_CASE(Integers_structors) {
    std::cout << "Integers ...structors" <<  std::endl;
{
        CASpp::Integer x(0);
        BOOST_REQUIRE(x==0);
    }
    {
        CASpp::Integer x(1);
        BOOST_REQUIRE(x==1);
    }
    {
        CASpp::Integer x("1");
        BOOST_REQUIRE(x==1);
    }
    {
        BOOST_REQUIRE_THROW(CASpp::Integer("z"),std::exception);
        BOOST_REQUIRE_THROW(CASpp::Integer("1/2"),std::exception);
    }
}
BOOST_AUTO_TEST_CASE(Numbers_structors) {
    std::cout << "Numbers ...structors" <<  std::endl;
#define CASPP_DO(WHAT) do {CASpp::Integer x(WHAT);std::cout << x << std::endl;} while(0)
    CASPP_DO(1234);
    CASPP_DO("1234");
    CASPP_DO("0x1234");
    CASPP_DO("01234");
#undef CASPP_DO
#define CASPP_DO(WHAT) do {CASpp::Integer i(WHAT);std::cout << std::hex << "0x" << i << std::endl;} while(0)
    CASPP_DO(1234);
    CASPP_DO("1234");
    CASPP_DO("0x1234");
    CASPP_DO("01234");
#undef CASPP_DO
#define CASPP_DO(WHAT) do {CASpp::Integer i(WHAT);std::cout << std::oct << "0"  << i << std::endl;} while(0)
    CASPP_DO(1234);
    CASPP_DO("1234");
    CASPP_DO("0x1234");
    CASPP_DO("01234");
#undef CASPP_DO
    {
        CASpp::Integer r(0);
        std::cout << r << std::endl;
    }
    {
        CASpp::Rational r(0);
        std::cout << r << std::endl;
    }
    {
        CASpp::Rational r(0,1);
        std::cout << r << std::endl;
    }
    {
        CASpp::Rational r("1/2");
        std::cout << r << std::endl;
    }
    {
        CASpp::Rational r("2/3");
        std::cout << r << std::endl;
    }
    std::cout << CASpp::Rational("1/2")*CASpp::Rational("2/3") << std::endl;
}
BOOST_AUTO_TEST_CASE(Rational_structors) {
    std::cout << "Rational_ ...structors" <<  std::endl;
    CASpp::Rational r;
    CASpp::Rational s(MYINTEGER(0));
    CASpp::Rational t("123");
    CASpp::Rational u("123/247");
    {
        CASpp::Integer n = numerator(u);
        BOOST_REQUIRE(n==MYINTEGER(123));
    }
    {
        CASpp::Integer n = denominator(u);
        BOOST_REQUIRE(n==MYINTEGER(247));
    }
}
BOOST_AUTO_TEST_CASE(Real_structors) {
    std::cout << "Real_ ...structors" <<  std::endl;
    CASpp::Real r1;
    std::string s = "0.421";
    CASpp::Real r2(s);
    std::cout << s << std::endl;
    std::cout << r2 << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Zero,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Up,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Down,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Away,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Nearest,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::NearestAway,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Significant,10) << std::endl;
    r2=(long double)(1.0e-23);
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Zero,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Up,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Down,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Away,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Nearest,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::NearestAway,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),0,CASpp::Rounding::Significant,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),12,CASpp::Rounding::Zero,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),12,CASpp::Rounding::Up,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),12,CASpp::Rounding::Down,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),12,CASpp::Rounding::Away,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),12,CASpp::Rounding::Nearest,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),12,CASpp::Rounding::NearestAway,10) << std::endl;
    std::cout << "r2:" << CASpp::Description<CASpp::GetNumberDot>()(r2,false,CASpp::GetNumberDot(),12,CASpp::Rounding::Significant,10) << std::endl;
}
BOOST_AUTO_TEST_CASE(Symbol_stuff) {
    std::cout << "Symbol stuff:" << std::endl;
    std::string d = "abcde";
    CASpp::Symbol s(d);
    BOOST_REQUIRE(s.name()==d);
    CASpp::SymbolRef ss(new CASpp::Symbol(d));
    BOOST_REQUIRE(ss->name()==d);
    ss = CASpp::SymbolRef(new CASpp::Symbol(s));
    BOOST_REQUIRE(ss->name()==d);
    d = "54321";
    ss.reset(new CASpp::Symbol(d));
    BOOST_REQUIRE(ss->name()==d);
    CASpp::Node n(ss);
    BOOST_REQUIRE(n.description()==d);
    d = "123123";
    n = CASpp::SymbolRef(new CASpp::Symbol(d));
    BOOST_REQUIRE(n.description()==d);
    n.symbolRef() = CASpp::SymbolRef(new CASpp::Symbol(d));
    BOOST_REQUIRE(n.description()==d);
    const CASpp::Node cn(ss);
    //cn = CASpp::SymbolRef(new CASpp::Symbol(d));
    //cn.symbolRef() = CASpp::SymbolRef(new CASpp::Symbol(d));
}
BOOST_AUTO_TEST_CASE(Variable_stuff) {
    std::cout << "Variable stuff:" << std::endl;
    std::string d = "abcde";
    CASpp::Variable s(d);
    BOOST_REQUIRE(s.name()==d);
    CASpp::VariableRef ss(new CASpp::Variable(d));
    BOOST_REQUIRE(ss->name()==d);
    ss = CASpp::VariableRef(new CASpp::Variable(s));
    BOOST_REQUIRE(ss->name()==d);
    d = "54321";
    ss.reset(new CASpp::Variable(d));
    BOOST_REQUIRE(ss->name()==d);
    CASpp::Node n(ss);
    BOOST_REQUIRE(n.description()==d);
    d = "123123";
    n = CASpp::VariableRef(new CASpp::Variable(d));
    BOOST_REQUIRE(n.description()==d);
    n.variableRef() = CASpp::VariableRef(new CASpp::Variable(d));
    BOOST_REQUIRE(n.description()==d);
    const CASpp::Node cn(ss);
    //cn = CASpp::VariableRef(new CASpp::Variable(d));
    //cn.variableRef() = CASpp::VariableRef(new CASpp::Variable(d));
}
BOOST_AUTO_TEST_CASE(Function_stuff) {
    std::cout << "Function stuff:" << std::endl;
    std::string d = "abcde";
    CASpp::NodeRef r = CASpp::makeFunctionNodeRef(d);
    CASPP_REQUIRE_BOOLEAN(d == r->description().substr(0,d.length()));
}
BOOST_AUTO_TEST_CASE(compare_stuff) {
    std::cout << "Compare stuff:" << std::endl;
    CASpp::Vector V;
#ifdef CASPP_DO
#   error change variable name
#endif
#define CASPP_DO(WHAT) do { \
        CASpp::Node * n = new CASpp::Node(WHAT); \
        std::cout << n->description() << "," << n->prettyType() << std::endl; \
        V.push_back(CASpp::NodeRef(n)); \
    } while(false)
    CASPP_DO(CASpp::Boolean::kUndefined);
    CASPP_DO(CASpp::Boolean::kTrue);
    CASPP_DO(CASpp::Boolean::kFalse);
    CASPP_DO(CASpp::Boolean::kUnknown);
#undef CASPP_DO
#define CASPP_DO(TYPE,WHAT) V.push_back(CASpp::make##TYPE##NodeRef(WHAT))
    CASPP_DO(String,"");
    CASPP_DO(String,"abcd");
    CASPP_DO(String,"abcde");
    CASPP_DO(String,"abde");
    CASPP_DO(Vector,"");
    CASPP_DO(Map,"");
    CASPP_DO(Integer,"0");
    CASPP_DO(Integer,"1234");
    CASPP_DO(Rational,"0");
    CASPP_DO(Rational,"12339/10");
    CASPP_DO(Rational,"1234/1");
    CASPP_DO(Rational,"12341/10");
    CASPP_DO(Real,"0");
    CASPP_DO(Real,"1233.9");
    CASPP_DO(Real,"1234");
    CASPP_DO(Real,"1234.1");
    CASPP_DO(Symbol,"abcd");
    CASPP_DO(Symbol,"abcde");
    CASPP_DO(Symbol,"abde");
    CASPP_DO(Variable,"abcd");
    CASPP_DO(Variable,"abcde");
    CASPP_DO(Variable,"abde");
    CASPP_DO(Function,"abcd");
    CASPP_DO(Function,"abcde");
    CASPP_DO(Function,"abde");
    //0, 4, 8, 9, 10, 12, 16, 20, 23, 26, end == 28
    BOOST_FOREACH(CASpp::NodeRef &n, V) {
        std::cout << n->description() << "," << n->prettyType() << std::endl;
    }
#undef CASPP_DO
#define CASPP_DO(i,j,k) BOOST_REQUIRE(CASpp::compare<CASpp::NodeRef>(V[i],V[j]).value()==CASpp::Comparison::k);\
    BOOST_REQUIRE(CASpp::compare<CASpp::NodeRef>(V[j],V[i]).value()==CASpp::Comparison(CASpp::Comparison::k).symmetrize().value())
    const size_t idx[] = {0, 4, 8, 9, 10, 12, 16, 20, 23, 26};
    size_t i,s,t;
    size_t j;
    s = t = 0;
    i = idx[t];
    j = i;CASPP_DO(i,j,kSame);
    j++;  CASPP_DO(i,j,kDifferent);
    j++;  CASPP_DO(i,j,kDifferent);
    j++;  CASPP_DO(i,j,kDifferent);
    j=idx[++t];  CASPP_DO(i,j,kUndefined);//String
    j=idx[++t];  CASPP_DO(i,j,kUndefined);//Vector
    j=idx[++t];  CASPP_DO(i,j,kUndefined);//Map
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Integer
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Rational
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Real
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Symbol
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Variable
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Function
    t = ++s;
    i = idx[t];
    j=i;  CASPP_DO(i,j,kSame);//String
    j++;  CASPP_DO(i,j,kAscending);
    j++;  CASPP_DO(i,j,kAscending);
    j++;  CASPP_DO(i,j,kAscending);
    j=idx[++t];  CASPP_DO(i,j,kUndefined);//Vector
    j=idx[++t];  CASPP_DO(i,j,kUndefined);//Map
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Integer
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Rational
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Real
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Symbol
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Variable
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Function
    ++i;
    j=i;  CASPP_DO(i,j,kSame);
    j++;  CASPP_DO(i,j,kAscending);
    j++;  CASPP_DO(i,j,kAscending);
    ++i;
    j=i;  CASPP_DO(i,j,kSame);
    ++j;  CASPP_DO(i,j,kAscending);
    t = ++s;
    i = idx[t];
    j=i;  CASPP_DO(i,j,kSame);//Vector
    j=idx[++t];  CASPP_DO(i,j,kUndefined);//Map
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Integer
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Rational
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Real
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Symbol
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Variable
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Function
    t = ++s;
    i = idx[t];
    j=i;  CASPP_DO(i,j,kSame);//Map
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Integer
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Rational
    j=idx[++t]; CASPP_DO(i,j,kUndefined);//Real
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Symbol
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Variable
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Function
    t = ++s;
    i = idx[t];
    j=i;  CASPP_DO(i,j,kSame);//Integer
    j++ ; CASPP_DO(i,j,kAscending);//Integer
    j=idx[++t]; CASPP_DO(i,j,kSame);//Rational
    j++ ; CASPP_DO(i,j,kAscending);//Rational
    j++ ; CASPP_DO(i,j,kAscending);//Rational
    j++ ; CASPP_DO(i,j,kAscending);//Rational
    j=idx[++t]; CASPP_DO(i,j,kSame);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Symbol
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Variable
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Function
    t = s;
    ++i;
    j=i;  CASPP_DO(i,j,kSame);//Integer
    j=idx[++t]; CASPP_DO(i,j,kDescending);//Rational
    j++ ; CASPP_DO(i,j,kDescending);//Rational
    j++ ; CASPP_DO(i,j,kSame);//Rational
    j++ ; CASPP_DO(i,j,kAscending);//Rational
    j=idx[++t]; CASPP_DO(i,j,kDescending);//Real
    j++ ; CASPP_DO(i,j,kDescending);//Real
    j++ ; CASPP_DO(i,j,kSame);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    t = ++s;
    i = idx[t];
    j=i;  CASPP_DO(i,j,kSame);//Rational
    j++ ; CASPP_DO(i,j,kAscending);//Rational
    j++ ; CASPP_DO(i,j,kAscending);//Rational
    j++ ; CASPP_DO(i,j,kAscending);//Rational
    j=idx[++t]; CASPP_DO(i,j,kSame);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Symbol
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Variable
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Function
    t = s;
    ++i;
    j=i;  CASPP_DO(i,j,kSame);//Rational
    j++ ; CASPP_DO(i,j,kAscending);//Rational
    j++ ; CASPP_DO(i,j,kAscending);//Rational
    j=idx[++t]; CASPP_DO(i,j,kDescending);//Real
    j++ ; CASPP_DO(i,j,kSame);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    t = s;
    ++i;
    j=idx[++t]; CASPP_DO(i,j,kDescending);//Real
    j++ ; CASPP_DO(i,j,kDescending);//Real
    j++ ; CASPP_DO(i,j,kSame);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    t = s;
    ++i;
    j=idx[++t]; CASPP_DO(i,j,kDescending);//Real
    j++ ; CASPP_DO(i,j,kDescending);//Real
    j++ ; CASPP_DO(i,j,kDescending);//Real
    j++ ; CASPP_DO(i,j,kSame);//Real
    t = ++s;
    i = idx[t];
    j=i; CASPP_DO(i,j,kSame);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Symbol
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Variable
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Function
    ++i;
    j=i; CASPP_DO(i,j,kSame);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    ++i;
    j=i; CASPP_DO(i,j,kSame);//Real
    j++ ; CASPP_DO(i,j,kAscending);//Real
    ++i;
    j=i; CASPP_DO(i,j,kSame);//Real
    t = ++s;
    i = idx[t];
    j=i; CASPP_DO(i,j,kSame);//Symbol
    j++ ; CASPP_DO(i,j,kAscending);//Symbol
    j++ ; CASPP_DO(i,j,kAscending);//Symbol
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Variable
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Function
    ++i;
    j=i; CASPP_DO(i,j,kSame);//Symbol
    j++ ; CASPP_DO(i,j,kAscending);//Symbol
    ++i;
    j=i; CASPP_DO(i,j,kSame);//Symbol
    t = ++s;
    i = idx[t];
    j=i; CASPP_DO(i,j,kSame);//Variable
    j++ ; CASPP_DO(i,j,kAscending);//Variable
    j++ ; CASPP_DO(i,j,kAscending);//Variable
    j=idx[++t]; CASPP_DO(i,j,kUnknown);//Function
    ++i;
    j=i; CASPP_DO(i,j,kSame);//Variable
    j++ ; CASPP_DO(i,j,kAscending);//Variable
    ++i;
    j=i; CASPP_DO(i,j,kSame);//Variable
    t = ++s;
    i = idx[t];
    j=i; CASPP_DO(i,j,kSame);//Function
    j++ ; CASPP_DO(i,j,kAscending);//Function
    j++ ; CASPP_DO(i,j,kAscending);//Function
    ++i;
    j=i; CASPP_DO(i,j,kSame);//Function
    j++ ; CASPP_DO(i,j,kAscending);//Function
    ++i;
    j=i; CASPP_DO(i,j,kSame);//Function
#undef CASPP_DO
}
BOOST_AUTO_TEST_CASE(SwappingListVector) {
    std::cout << "Testing swap List <-> Vector..." <<  std::endl;
    CASpp::NodeRef lR = CASpp::makeListNodeRef("");
    CASpp::NodeRef vR = CASpp::makeVectorNodeRef("");
    CASpp::NodeRef nRa = CASpp::makeSymbolNodeRef("adf");
    CASpp::NodeRef nRb = CASpp::makeSymbolNodeRef("bjd");
    BOOST_REQUIRE(nRa!=nRb);
    lR->listRef()->push_back(nRa);
    BOOST_REQUIRE(lR->listRef()->back()==nRa);
    BOOST_REQUIRE(lR->listRef()->back()!=nRb);
    vR->vectorRef()->push_back(nRb);
    BOOST_REQUIRE(vR->vectorRef()->back()!=nRa);
    BOOST_REQUIRE(vR->vectorRef()->back()==nRb);
    vR->vectorRef()->swap(*lR->listRef());
    BOOST_REQUIRE(lR->listRef()->back()!=nRa);
    BOOST_REQUIRE(lR->listRef()->back()==nRb);
    BOOST_REQUIRE(vR->vectorRef()->back()==nRa);
    BOOST_REQUIRE(vR->vectorRef()->back()!=nRb);
    lR->listRef()->swap(*vR->vectorRef());
    BOOST_REQUIRE(lR->listRef()->back()==nRa);
    BOOST_REQUIRE(lR->listRef()->back()!=nRb);
    BOOST_REQUIRE(vR->vectorRef()->back()!=nRa);
    BOOST_REQUIRE(vR->vectorRef()->back()==nRb);
    std::cout << "Done" <<  std::endl;
}
#endif
